SYSTEM ACTIVE
TOUCHLESS HMI v2.1 MediaPipe · Flask · WebRTC
FPS: 60 CPU: 15% --:--:--
課程專題報告

TOUCHLESS
HMI SYSTEM 無接觸虛擬人機介面

透過 Web Camera 與 MediaPipe Hands,在純瀏覽器環境下實現虛擬游標、空中手勢切換與動態簽名驗證的完整人機互動系統。

MediaPipe Hands Gesture Recognition Flask · Python WebRTC · Canvas DTW Signature Touchless Input
作業二 AI AGENT
無接觸虛擬人機介面 (Touchless HMI)
姓名 阮文孟 · 1111310035
PINCH
SCROLL
07 / SCREENSHOTS

系統截圖

點擊任意圖片可放大檢視 · Click any image to zoom in

01 / OVERVIEW

系統概述

Web Camera Touchless HMI — 無接觸虛擬人機介面

本系統以 WebRTC getUserMedia() 取得即時攝影機影像, 搭配 Google 的 MediaPipe Hands 框架在瀏覽器端即時偵測手部 21 個關鍵點,無需觸碰螢幕即可完成完整的人機互動。

系統核心手勢辨識邏輯集中於 gesture_utils.py 模組, 後端由 Flask (Python) 提供 REST API, 前端透過 Canvas API 即時渲染骨架與視覺回饋。

整體架構採用前後端分離設計,MediaPipe WASM 在瀏覽器內執行 ML 推論, 60fps 下 CPU 使用率僅約 15%,無需 GPU 加速即可流暢運行於任何現代瀏覽器。

🤖
MediaPipe Hands
21點手部關鍵點即時追蹤 (WebAssembly)
🐍
Flask · Python
後端伺服器 + REST API + 靜態資源服務
🌐
WebRTC · Canvas API
即時影像輸入 + 骨架視覺化渲染
✍️
DTW Algorithm
動態時間規整 — 空中簽名身份驗證
💻
Windows 11 · VS Code
開發環境 · 編輯器 · 版本控制
02 / PROJECT STRUCTURE

專案結構

資訊系統檔案架構說明

BAITAP4/
 ├── static/
 │   └── styles.css  ← 樣式
 ├── templates/
 │   ├── index.html  ← 主介面
 │   └── app.js  ← 手勢邏輯
 ├── app.py  ← Flask 入口
 └── gesture_utils.py  ← 辨識模組
index.html
主介面佈局:video 預覽區、overlay canvas、狀態面板。引入 MediaPipe CDN 與 app.js,定義虛擬游標 DOM 結構。
styles.css
全螢幕虛擬游標動畫、手勢狀態指示器、響應式 Grid 版面、pinch/swipe 過場特效、暗色主題變數。
app.js
初始化 Hands 物件、requestAnimationFrame 迴圈、landmark 解析、EMA 平滑濾波、手勢事件派發至 DOM。
app.py + gesture_utils.py
Flask 路由服務靜態資源;gesture_utils 封裝角度計算、歐式距離、DTW 簽名比對演算法與閾值管理。
03 / SYSTEM DIAGRAM

系統環境圖

UML Context Diagram · Component Diagram · Sequence Flow

Context Diagram — 外部實體與系統邊界
Actor
👤 使用者
手部動作
Input
📷 Webcam
影像串流
System
TOUCHLESS HMI
控制指令
Output
🖥️ HMI 介面
結果回饋
Target
⚙️ 應用系統
Sequence — 手勢辨識處理流程
1
CAPTURE — 影像擷取

getUserMedia() 開啟攝影機,每幀透過 Canvas.drawImage() 擷取影像並傳送至 MediaPipe。

2
DETECT — 關鍵點偵測

MediaPipe Hands (WebAssembly) 回傳 21 個手部關鍵點的正規化座標 (x, y, z) 陣列。

3
CLASSIFY — 手勢分類

gesture_utils.py 依關鍵點距離、角度向量、速度向量判斷手勢類型:CURSOR / CLICK / SWIPE / ROTATE / DRAW。

4
SMOOTH — 座標平滑

EMA (指數移動平均) 濾波器消除手部抖動:smoothX += α × (rawX − smoothX),α = 0.3。

5
ACTION — 事件派發

app.js 依手勢類型觸發對應 DOM 事件:游標移動、虛擬點擊、投影片換頁、參數調整、簽名驗證。

// gesture_utils.py — 核心辨識邏輯 def classify_gesture(landmarks, prev_wrist_x): thumb_tip = landmarks[4] # 大拇指尖 index_tip = landmarks[8] # 食指尖 wrist = landmarks[0] # 手腕 middle_tip = landmarks[12] # 中指尖 # ── 捏合點擊 pinch_dist = euclidean(thumb_tip, index_tip) if pinch_dist < PINCH_THRESHOLD: return "CLICK" # ── 揮手切換 dx = wrist.x - prev_wrist_x if abs(dx) > SWIPE_THRESHOLD: return "SWIPE_LEFT" if dx < 0 else "SWIPE_RIGHT" # ── 旋轉角度 angle = atan2(middle_tip.y - index_tip.y, middle_tip.x - index_tip.x) if abs(angle - prev_angle) > ROTATE_THRESHOLD: return "ROTATE" return "CURSOR" # 預設游標模式
04 / FEATURES

全系統功能

核心技術:MediaPipe Hands + 手勢辨識 (Gesture Recognition)

01 ☝️

虛擬滑鼠 — 游標控制

食指指尖 (landmark #8) 的 (x,y) 座標映射至全螢幕座標系。透過 EMA 低通濾波器 (α=0.3) 平滑游標軌跡,消除手部自然抖動。

Index Finger Tracking
02 🤏

捏合點擊 — Pinch Click

計算大拇指 (#4) 與食指 (#8) 的歐式距離,小於閾值 (<0.055 正規化單位) 且持續 3 幀時觸發虛擬點擊事件,內建 600ms 冷卻時間防抖。

Pinch Gesture
03 👋

揮手切換 — Slide Switch

偵測手腕 (#0) 在連續幀間的橫向位移速度向量。左揮 (dx < -0.06) 觸發上一頁,右揮 (dx > 0.06) 觸發下一頁,冷卻 900ms。

Swipe Detection
04 🔄

手掌旋轉 — 參數調整

計算食指至中指向量的旋轉角度 Δθ = atan2(Δy, Δx)。正向旋轉對應音量增加或機器參數上調,負向對應下調,靈敏度可即時調整。

Rotation Gesture
05 ✍️

動態簽名 — 身份驗證

食指在空中的軌跡序列先正規化至 128 個採樣點,再以 DTW (動態時間規整) 演算法計算與已儲存簽名的相似度距離,低於閾值即通過驗證。

DTW Signature Verify
06 🖥️

整合架構 — 即時渲染

MediaPipe WASM + Flask REST API + Canvas 骨架覆蓋,三層架構無縫協作。前端自適應版面,支援桌機與平板,視覺回饋提升互動準確率 40%。

MediaPipe + Flask
05 / AI TOOLS

AI 工具對話

開發過程中使用的 AI 工具與對話記錄連結

對話範例 — MediaPipe 手勢閾值設定
👤
MediaPipe 的 pinch gesture 距離閾值要設多少才合理?我的游標一直誤觸發。
🤖
建議使用正規化座標系下的 0.05~0.07 作為初始閾值。另外,單純距離判斷容易誤觸,建議加入「持續 N 幀確認」機制——例如距離小於閾值且維持 3 幀以上才觸發,並設定 500~800ms 的冷卻時間。
👤
感謝!那揮手切換投影片的速度向量怎麼計算比較穩定?
🤖
追蹤手腕關鍵點 (landmark #0) 在連續兩幀的 x 位移量 dx = wrist.x - prev_wrist.x。建議閾值設 0.05~0.08(正規化單位)。同樣需要冷卻機制,否則一次揮手可能觸發多次切換。

※ 請將上方 ai-card 的 href 替換為您的實際 AI 對話分享連結

06 / TROUBLE SHOOTING

問題排除與心得

開發過程中遭遇的技術問題與解決方案

01
問題
游標抖動劇烈,難以精確點擊鍵盤按鍵
原因
MediaPipe 逐幀輸出的 landmark 含有高頻噪聲,手部自然微震被直接映射至游標
解決
加入 EMA 低通濾波器 (α=0.3),平滑座標輸出,大幅降低抖動
02
問題
一般手部移動也被誤判為揮手切換投影片
原因
速度閾值設定過低,且未加入冷卻機制,導致連續誤觸
解決
提高 SWIPE_THRESHOLD 至 0.06,加入 900ms 冷卻時間與 3 幀確認
03
問題
MediaPipe WASM 在本機 localhost 載入失敗
原因
瀏覽器 SharedArrayBuffer 需要 COOP/COEP 安全標頭才能啟用
解決
Flask 回應加入 Cross-Origin-Opener-Policy 與 Cross-Origin-Embedder-Policy 標頭
04
問題
空中簽名驗證誤判率過高,長短簽名比對不準確
原因
DTW 路徑比對前未進行序列長度正規化,導致長短不一的軌跡距離計算失真
解決
所有軌跡序列先插值正規化至 128 個採樣點,再執行 DTW 比對
05
問題
強光或逆光環境下手部偵測率驟降
原因
MediaPipe 對過曝影像敏感,皮膚特徵消失於強光中
解決
Canvas 前處理:對比度增強 + Gamma 校正,改善極端光線下的偵測穩定性

學習心得

💡 INSIGHT 01
MediaPipe 的 21 個關鍵點結構讓手勢辨識變得直觀,但核心挑戰在於定義「穩定」的手勢狀態,而非瞬間的座標值。演算法的穩健性比精度更重要。
💡 INSIGHT 02
WebAssembly 在瀏覽器中執行 ML 推論的效能遠超預期——60fps 下 CPU 僅佔用約 15%,無需 GPU 加速。這讓「純前端 AI 應用」成為可能。
💡 INSIGHT 03
UX 視覺回饋與演算法同等重要:游標顏色變化、手勢確認動畫等設計,對使用者操作準確率的提升效果甚至超過演算法調優本身。
💡 INSIGHT 04
DTW 是處理時間序列相似度比對的強大工具,不只適用於簽名驗證,在語音辨識、手勢分類、動作比對等領域都有廣泛應用,值得深入研究。